/*
 * $Id: errno.c,v 1.6 2006-04-03 11:32:48 bacon Exp $
 */

#include <xp/bas/errno.h>

#ifdef _WIN32

#ifdef XP_WINSOCK_IN_ORDER
#include <windows.h>
#include <winsock2.h>
#else
#include <winsock2.h>
#include <windows.h>
#endif

/* size of the table */
#define TABLESIZE(x) (sizeof(x)/sizeof(x[0]))

/* The following two constants must be the minimum and maximum
   values in the (contiguous) range of Exec Failure errors. */
#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN

/* These are the low and high value in the range of errors that are
   access violations */
#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED

struct errentry 
{
        unsigned long oscode;   /* OS return value */
        int errnocode;  /* System V error code */
};

struct errentry_wsa 
{
        int oscode;
        int errnocode;
};

static struct errentry __errtable[] = 
{
        {  ERROR_INVALID_FUNCTION,       XP_EINVAL    },  /* 1 */
        {  ERROR_FILE_NOT_FOUND,         XP_ENOENT    },  /* 2 */
        {  ERROR_PATH_NOT_FOUND,         XP_ENOENT    },  /* 3 */
        {  ERROR_TOO_MANY_OPEN_FILES,    XP_EMFILE    },  /* 4 */
        {  ERROR_ACCESS_DENIED,          XP_EACCES    },  /* 5 */
        {  ERROR_INVALID_HANDLE,         XP_EBADF     },  /* 6 */
        {  ERROR_ARENA_TRASHED,          XP_ENOMEM    },  /* 7 */
        {  ERROR_NOT_ENOUGH_MEMORY,      XP_ENOMEM    },  /* 8 */
        {  ERROR_INVALID_BLOCK,          XP_ENOMEM    },  /* 9 */
        {  ERROR_BAD_ENVIRONMENT,        XP_E2BIG     },  /* 10 */
        {  ERROR_BAD_FORMAT,             XP_ENOEXEC   },  /* 11 */
        {  ERROR_INVALID_ACCESS,         XP_EINVAL    },  /* 12 */
        {  ERROR_INVALID_DATA,           XP_EINVAL    },  /* 13 */
        {  ERROR_INVALID_DRIVE,          XP_ENOENT    },  /* 15 */
        {  ERROR_CURRENT_DIRECTORY,      XP_EACCES    },  /* 16 */
        {  ERROR_NOT_SAME_DEVICE,        XP_EXDEV     },  /* 17 */
        {  ERROR_NO_MORE_FILES,          XP_ENOENT    },  /* 18 */
        {  ERROR_LOCK_VIOLATION,         XP_EACCES    },  /* 33 */
        {  ERROR_BAD_NETPATH,            XP_ENOENT    },  /* 53 */
        {  ERROR_NETWORK_ACCESS_DENIED,  XP_EACCES    },  /* 65 */
        {  ERROR_BAD_NET_NAME,           XP_ENOENT    },  /* 67 */
        {  ERROR_FILE_EXISTS,            XP_EEXIST    },  /* 80 */
        {  ERROR_CANNOT_MAKE,            XP_EACCES    },  /* 82 */
        {  ERROR_FAIL_I24,               XP_EACCES    },  /* 83 */
        {  ERROR_INVALID_PARAMETER,      XP_EINVAL    },  /* 87 */
        {  ERROR_NO_PROC_SLOTS,          XP_EAGAIN    },  /* 89 */
        {  ERROR_DRIVE_LOCKED,           XP_EACCES    },  /* 108 */
        {  ERROR_BROKEN_PIPE,            XP_EPIPE     },  /* 109 */
        {  ERROR_DISK_FULL,              XP_ENOSPC    },  /* 112 */
        {  ERROR_INVALID_TARGET_HANDLE,  XP_EBADF     },  /* 114 */
        {  ERROR_INVALID_HANDLE,         XP_EINVAL    },  /* 124 */
        {  ERROR_WAIT_NO_CHILDREN,       XP_ECHILD    },  /* 128 */
        {  ERROR_CHILD_NOT_COMPLETE,     XP_ECHILD    },  /* 129 */
        {  ERROR_DIRECT_ACCESS_HANDLE,   XP_EBADF     },  /* 130 */
        {  ERROR_NEGATIVE_SEEK,          XP_EINVAL    },  /* 131 */
        {  ERROR_SEEK_ON_DEVICE,         XP_EACCES    },  /* 132 */
        {  ERROR_DIR_NOT_EMPTY,          XP_ENOTEMPTY },  /* 145 */
        {  ERROR_NOT_LOCKED,             XP_EACCES    },  /* 158 */
        {  ERROR_BAD_PATHNAME,           XP_ENOENT    },  /* 161 */
        {  ERROR_MAX_THRDS_REACHED,      XP_EAGAIN    },  /* 164 */
        {  ERROR_LOCK_FAILED,            XP_EACCES    },  /* 167 */
        {  ERROR_ALREADY_EXISTS,         XP_EEXIST    },  /* 183 */
        {  ERROR_FILENAME_EXCED_RANGE,   XP_ENOENT    },  /* 206 */
        {  ERROR_NESTING_NOT_ALLOWED,    XP_EAGAIN    },  /* 215 */
        {  ERROR_NOT_ENOUGH_QUOTA,       XP_ENOMEM    }   /* 1816 */
};

static struct errentry_wsa __errtable_wsa[] = 
{
	{ WSAEINTR,            XP_EINTR },
	{ WSAEACCES,           XP_EACCES },
	{ WSAEFAULT,           XP_EFAULT },
	{ WSAEINVAL,           XP_EINVAL },
	{ WSAEMFILE,           XP_EMFILE },

	{ WSAEADDRINUSE,       XP_EADDRINUSE },
	{ WSAEADDRNOTAVAIL,    XP_EADDRNOTAVAIL },
	{ WSAEALREADY,         XP_EALREADY },
	{ WSAEAFNOSUPPORT,     XP_EAFNOSUPPORT },

	{ WSAECONNABORTED,     XP_ECONNABORTED },
	{ WSAECONNREFUSED,     XP_ECONNREFUSED },
	{ WSAECONNRESET,       XP_ECONNRESET },

	{ WSAEINPROGRESS,      XP_EINPROGRESS },

	{ WSAENETDOWN,         XP_ENETDOWN },
	{ WSAENETRESET,        XP_ENETRESET },
	{ WSAENETUNREACH,      XP_ENETUNREACH },

	{ WSAENOTCONN,         XP_ENOTCONN },
	{ WSAENOTSOCK,         XP_ENOTSOCK },

	{ WSAEPROTONOSUPPORT,  XP_EPROTONOSUPPORT },
	{ WSAETIMEDOUT,        XP_ETIMEDOUT },
	{ WSAEWOULDBLOCK,      XP_EWOULDBLOCK }

/* TODO: add more here ... */
};

int xp_maperrno (unsigned long oserrno)
{
        int i;

        /* check the table for the OS error code */
        for (i = 0; i < TABLESIZE(__errtable); ++i) {
                if (oserrno == __errtable[i].oscode) {
                        return __errtable[i].errnocode;
                }
        }

        /* The error code wasn't in the table.  We check for a range of */
        /* EACCES errors or exec failure errors (ENOEXEC).  Otherwise   */
        /* EINVAL is returned.                                          */

        if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE)
                return XP_EACCES;
        else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR)
                return XP_ENOEXEC;
        else
                return XP_EINVAL;
}

int xp_maperrno_wsa (int oserrno)
{
        int i;

        for (i = 0; i < TABLESIZE(__errtable_wsa); ++i) {
                if (oserrno == __errtable_wsa[i].oscode) {
                        return __errtable_wsa[i].errnocode;
                }
        }

	return XP_EINVAL;
} 

#endif

int xp_geterrno (void)
{
	return xp_errno;
}

void xp_seterrno (int num)
{
	xp_errno = num;
}
